/**
 *
 */
package name.yzhu.httpserver;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServlet;

import name.yzhu.common.CommonConstant;
import name.yzhu.common.lang.DoubleKeyMap;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.webapp.WebAppContext;

/**
 * An encapsulation of JETTY components;
 *
 * Add SERVLETS or set web page root path are enough for starting a http server.</br></br>
 *
 * NOTE: you should set all arguments before starting server.</br></br>
 *
 *
 * default accept queue is 50 <br>
 * default port is 100020 <br>
 * default acceptor's number is ( the number of core/2+1) </br>
 * default thread pool size is equals (the number of accepotors *3) <br>
 * default max form content is 2M bytes <br>
 *
 * bug: there is some trouble in processing jsp<br><br>
 *
 * Here is a simple example for starting a sever with web and servlets:</br>
 * <pre>
 *         HTTPServletServer cjss=new HTTPServletServer();
 *         cjss.setPort(port);
 *         cjss.setThreadPoolSize(20);
 *         cjss.setAcceptQueueSize(50);
 *         	cjss.setWebBase("web/");
 *         	cjss.setWebRootpath("/");
 *         	cjss.addWebServlet(new xxxaServlet(), "/xa");
 *         cjss.addWebServlet(new xxxbServlet(), "/xb");
 *         	cjss.addWelcomePage("/index.jsp");
 *         	cjss.start();
 *         	hjss.join();
 * </pre>
 * @author yhzhu
 *
 */
public class HTTPServletServer extends AbstractHttpServer {
//	private static final Log LOG = LogFactory.getLog(HTTPServletServer.class);
	
	private String webBase = null;
	private String webRootpath = "web";
	private List<String> welcomes=new ArrayList<String>();
	private int maxFormContent = (int) (CommonConstant.NUM_1M * 2);
	private List<Pair<String, HttpServlet>> webPathServlet
                = new ArrayList<Pair<String, HttpServlet>>();
	private DoubleKeyMap<String, String, HttpServlet> path2Servlet
                      = new DoubleKeyMap<String, String, HttpServlet>();

	private IServerAdminable admin = null;

	public HTTPServletServer(IServerAdminable admin) {
		this.admin  = admin;
	}
	
	protected void initialContexts() {
		ContextHandlerCollection contexts = new ContextHandlerCollection();
		if (webBase != null) {
			WebAppContext webApp = new WebAppContext();
			webApp.setContextPath(webRootpath);
			webApp.setResourceBase(webBase);
			webApp.setParentLoaderPriority(true);

			if(this.welcomes.size()>0){
				webApp.setWelcomeFiles(this.welcomes.toArray(new String[0]));
			}

			for (Pair<String, HttpServlet> ws : webPathServlet) {
				webApp.addServlet(new ServletHolder(ws.getValue()), ws.getKey());
			}

			if (this.path2Servlet.get(this.webRootpath) != null) {
				for (Entry<String, HttpServlet> ps : this.path2Servlet.get(this.webRootpath).entrySet()) {
					webApp.addServlet(new ServletHolder(ps.getValue()), ps.getKey());
				}
				this.path2Servlet.remove(this.webRootpath);
			}

			webApp.setMaxFormContentSize(maxFormContent);
			contexts.addHandler(webApp);
		}


		if (this.path2Servlet.size() > 0) {
			for (Entry<String, Map<String, HttpServlet>> ps : this.path2Servlet.entrySet()) {
				ServletContextHandler servletContext
				    = new ServletContextHandler(ServletContextHandler.SESSIONS);
				servletContext.setContextPath(ps.getKey());
				for (Entry<String, HttpServlet> m : ps.getValue().entrySet()) {
					servletContext.addServlet(new ServletHolder(m.getValue()), m.getKey());
				}
				servletContext.setMaxFormContentSize(maxFormContent);
				contexts.addHandler(servletContext);
			}
		}

		server.setHandler(contexts);
	}

	

	public void addServlet(AbstractHttpServlet servlet) {
		admin.addServlet(servlet);
		path2Servlet.put(servlet.getContextRoot(), servlet.getContextPath(), servlet);
	}

	public void addServlet(String contextRoot,String path,HttpServlet servlet){
		path2Servlet.put(contextRoot, path, servlet);
	}

	public void addWebServlet(HttpServlet servlet, String webServletContext){
		webPathServlet.add(new ImmutablePair<String, HttpServlet>(webServletContext, servlet));
	}

	/**
	 * @return the webBase
	 */
	public String getWebBase() {
		return webBase;
	}

	/**
	 * @param webBase the webBase to set
	 */
	public void setWebBase(String webBase) {
		this.webBase = webBase;
	}

	/**
	 * @return the webRootpath
	 */
	public String getWebRootpath() {
		return webRootpath;
	}

	/**
	 * @param webRootpath the webRootpath to set
	 */
	public void setWebRootpath(String webRootpath) {
		this.webRootpath = webRootpath;
	}

	/**
	 * @return the welcomes
	 */
	public List<String> getWelcomes() {
		return welcomes;
	}

	/**
	 * @param welcomes the welcomes to set
	 */
	public void addWelcomePage(final String page) {
		this.welcomes.add(page);
	}

	/**
	 * @return the maxFormContent
	 */
	public int getMaxFormContent() {
		return maxFormContent;
	}

	/**
	 * @param maxFormContent the maxFormContent to set
	 */
	public void setMaxFormContent(int maxFormContent) {
		this.maxFormContent = maxFormContent;
	}

	@Override
	protected ServerType getServerType() {
		return AbstractHttpServer.ServerType.Servlet;
	}
}
